/*
@file: ast.cpp
@author: ZZH
@date: 2022-03-09
@info: 抽象语法树
*/
#include <string>
#include <QMessageBox>
#include <QListWidgetItem>
#include "ast.h"
#include "compiler.h"
#include "symTable.h"
#include "bufferAllocator.h"

bool ASTAdaptor_t::isDirty(void) const
{
    auto& compiler = Compiler_t::getInst();
    bool res = false;

    if (true == compiler.recPush()) {
        res = this->child->isDirty();
        compiler.recPop();
    } else {
        throw QObject::tr(
            "Signal recursion overflow, max value is 15, please check if you are using circular "
            "reference or a signal reference it self");
    }
    return res;
}

void ASTFunctionCall_t::calculate(BasicType* output) const
{
    if (nullptr == output)
        return;

    auto& calculator = Calculator_t::getInst();

    FunCallArg_t funArgs = {
        calculator.getTotolPoint(),
        calculator.getFS(),
        calculator.getPT(),
        nullptr,
    };

    int argLen = 0;
    size_t memSize = calculator.getMemSizeToAlloc();

    if (nullptr != this->args) {
        argLen = args->length();
        funArgs.args = new void*[argLen];

        if (0 != argLen) {
            for (int i = 0; i < argLen; i++) {
                funArgs.args[i] = BufferAllocator::getRawBuffer(memSize);
                this->args->at(i)->calculate(reinterpret_cast<BasicType*>(funArgs.args[i]));
            }
        }
    }

    // memset(output, 0, memSize);//默认在Allocator里设0
    this->Calcb(&funArgs, output);

    for (int i = 0; i < argLen; i++) BufferAllocator::freeBuffer(funArgs.args[i]);

    if (nullptr != funArgs.args)
        delete[] funArgs.args;
}

void ASTOperator_t::calculate(BasicType* output) const
{
    if (nullptr == output)
        return;

    const Calculator_t& calculator = Calculator_t::getInst();

    int allNum = calculator.getTotolPoint();
    size_t memSize = calculator.getMemSizeToAlloc();

    BasicType* lVal = BufferAllocator::getBuffer<BasicType>(memSize);
    this->left->calculate(lVal);

    BasicType* rVal = BufferAllocator::getBuffer<BasicType>(memSize);
    this->right->calculate(rVal);

    switch (this->op) {
        case '+': {
            for (int i = 0; i < allNum; i++) output[i] = lVal[i] + rVal[i];
        } break;

        case '-': {
            for (int i = 0; i < allNum; i++) output[i] = lVal[i] - rVal[i];
        } break;

        case '*': {
            for (int i = 0; i < allNum; i++) output[i] = lVal[i] * rVal[i];
        } break;

        case '/': {
            for (int i = 0; i < allNum; i++) {
                if (rVal[i] != 0)
                    output[i] = lVal[i] / rVal[i];
            }
        } break;

        case '%': {
            for (int i = 0; i < allNum; i++) output[i] = std::fmod(lVal[i], rVal[i]);
        } break;

        case '^': {
            for (int i = 0; i < allNum; i++) output[i] = powf(lVal[i], rVal[i]);
        } break;

        case '>': {
            for (int i = 0; i < allNum; i++) output[i] = lVal[i] > rVal[i];
        } break;

        case '<': {
            for (int i = 0; i < allNum; i++) output[i] = lVal[i] < rVal[i];
        } break;

        case '&': {
            for (int i = 0; i < allNum; i++) output[i] = (uint32_t) lVal[i] & (uint32_t) rVal[i];
        } break;

        case '|': {
            for (int i = 0; i < allNum; i++) output[i] = (uint32_t) lVal[i] | (uint32_t) rVal[i];
        } break;
    }

    BufferAllocator::freeBuffer(lVal);
    BufferAllocator::freeBuffer(rVal);
}

void ASTCompare_t::calculate(BasicType* output) const
{
    if (nullptr == output)
        return;

    const Calculator_t& calculator = Calculator_t::getInst();

    int allNum = calculator.getTotolPoint();
    size_t memSize = calculator.getMemSizeToAlloc();

    BasicType* lVal = BufferAllocator::getBuffer<BasicType>(memSize);
    this->left->calculate(lVal);

    BasicType* rVal = BufferAllocator::getBuffer<BasicType>(memSize);
    this->right->calculate(rVal);

    switch (this->op) {
        case ASTCompare_t::EQU: {
            for (int i = 0; i < allNum; i++) output[i] = lVal[i] == rVal[i];
        } break;

        case ASTCompare_t::NEQU: {
            for (int i = 0; i < allNum; i++) output[i] = lVal[i] != rVal[i];
        } break;

        case ASTCompare_t::GEQU: {
            for (int i = 0; i < allNum; i++) output[i] = lVal[i] >= rVal[i];
        } break;

        case ASTCompare_t::LEQU: {
            for (int i = 0; i < allNum; i++) output[i] = lVal[i] <= rVal[i];
        } break;

        case ASTCompare_t::BAND: {
            for (int i = 0; i < allNum; i++) output[i] = (lVal[i] != 0) && (rVal[i] != 0);
        } break;

        case ASTCompare_t::BOR: {
            for (int i = 0; i < allNum; i++) output[i] = (lVal[i] != 0) || (rVal[i] != 0);
        } break;
    }

    BufferAllocator::freeBuffer(lVal);
    BufferAllocator::freeBuffer(rVal);
}

void ASTCondition_t::calculate(BasicType* output) const
{
    const Calculator_t& calculator = Calculator_t::getInst();

    int allNum = calculator.getTotolPoint();
    size_t memSize = calculator.getMemSizeToAlloc();

    if (nullptr != this->cond and nullptr != this->left and nullptr != this->right) {
        BasicType* condRes = BufferAllocator::getBuffer<BasicType>(memSize);
        BasicType* leftRes = BufferAllocator::getBuffer<BasicType>(memSize);
        BasicType* rightRes = BufferAllocator::getBuffer<BasicType>(memSize);

        this->cond->calculate(condRes);
        this->left->calculate(leftRes);
        this->right->calculate(rightRes);

        for (int i = 0; i < allNum; i++) output[i] = 0 != condRes[i] ? leftRes[i] : rightRes[i];

        BufferAllocator::freeBuffer(condRes);
        BufferAllocator::freeBuffer(leftRes);
        BufferAllocator::freeBuffer(rightRes);
    } else {
        for (int i = 0; i < allNum; i++) output[i] = 0;
    }
}

void ASTDynamicNumber_t::calculate(BasicType* output) const
{
    const Calculator_t& calculator = Calculator_t::getInst();
    int allNum = calculator.getTotolPoint();
    BasicType fs = calculator.getFS();

    switch (this->type) {
        case VariableT:
            for (int i = 0; i < allNum; i++) output[i] = calculator.getT(i);
            break;

        case VariableN:
            for (int i = 0; i < allNum; i++) output[i] = allNum;
            break;

        case VariableFS:
            for (int i = 0; i < allNum; i++) output[i] = fs;
            break;

        case VariableI:
            for (int i = 0; i < allNum; i++) output[i] = i;
            break;

        default: memset(output, 0, calculator.getMemSizeToAlloc()); break;
    }
}

void ASTList_t::calculate(BasicType* output) const
{
    const Calculator_t& calculator = Calculator_t::getInst();

    int allNum = calculator.getTotolPoint();
    size_t memSize = calculator.getMemSizeToAlloc();

    memset(output, 0, memSize);

    if (nullptr == this->members)
        return;

    BasicType* buf = BufferAllocator::getBuffer<BasicType>(memSize);
    int listLen = this->members->length();
    int copyLen = listLen < allNum ? listLen : allNum, i = 0;

    // 只有一个成员时, 整个list使用这个成员进行填充
    if (1 == listLen) {
        copyLen = 0; // 此处自行完成填充, 下面不再拷贝
        auto pm = this->members->at(0);
        if (nullptr != pm) {
            pm->calculate(buf);
            for (i = 0; i < allNum; i++) output[i] = buf[0];
        }
    }

    for (i = 0; i < copyLen; i++) {
        auto pm = this->members->at(i);
        if (nullptr != pm) {
            pm->calculate(buf);
            output[i] = buf[0];
        }
    }

    BufferAllocator::freeBuffer(buf);
}
